架构实战:基于条件配置的简单规则引擎实现
规则引擎是大型系统必不可少的一个组件,基于规则引擎可以实现灵活的规则和控制功能。本文从需求出发,介绍了一种简单且高效的实现规则引擎的方案。
第一章需求概述
规则引擎的应用可以说非常的广泛,规则引擎可以分为基于条件配置的简单规则引擎和基于数据分析统计的复杂的规则引擎,本文档主要讨论的是基于条件配置的简单规则引擎实现。
1.1 业务场景示例
需要实现根据医生诊断的症状来展示可以使用的药品,比如一个女患者被医生诊断为:气血两虚,身体瘦弱,腰膝酸软,月经不调,那么系统会根据这些症状展示合适的调理药品乌鸡白凤丸。
1.2 业务分析抽象
现在我们来分析一下药品推荐系统的场景。患者首先是个女的,那么有一个条件是性别为女;气血的诊断情况为两虚;身体状况为瘦弱;腰膝情况是酸软,月经的状态是不协调。如果满足了这些条件的话,那么系统要为医生展示推荐药品乌鸡白凤丸。
通过上述分析,我们可以比较容易得出一个抽象场景:即症状符合了规则,就展示推介的结果,其中规则是由一系列的条件所组成的,当所有的条件都满足了,那么就符合了规则。
分析完之后,是不是觉得豁然开朗了。下面我们来看一下具体要怎么去设计。
第二章系统设计实现
本章主要结合上一章节业务分析抽象的内容讨论简单的数据库结构设计和系统编码实现。
2.1 数据库设计
2.1.1 症状规则表
症状规则表
数据项 | 类型 | 备注 |
规则ID | 文本 | 主键 |
规则名称 | 文本 | 名称 |
规则表达式 | 文本 | 条件表达式 |
表达式描述 | 文本 | 表达式描述 |
2.1.2 症状条件表
症状条件表
数据项 | 类型 | 备注 |
条件ID | 文本 | 主键 |
条件名称 | 文本 | 名称 |
条件标识符 | 文本 | 条件的唯一标识符 |
条件编码 | 文本 | 条件的key编码(如:性别=sex) |
条件计算方式 | 文本 | 计算方式(如:等于,大于,小于,包含…) |
条件值 | 文本 | 条件的值(如:女=femal 或者女=0) |
规则ID | 文本 | 规则ID值 |
2.1.3 展示结果表
展示结果表
数据项 | 类型 | 备注 |
结果ID | 文本 | 主键 |
结果名称 | 文本 | 结果的描述 |
规则ID | 文本 | 规则ID值 |
2.1.4 数据存储示例
症状规则表
规则ID | 规则名称 | 规则表达式 | 表达式描述 |
1001 | 乌鸡白凤丸规则 | (A1 && A2 && A3 && A4 && A5) | 性别等于femal 而且 气血等于weak 而且 身体状况等于thin 而且 腰膝情况等于limp 而且 月经状态等于menoxenia |
症状条件表
条件ID | 条件名称 | 条件标识符 | 条件编码 | 计算方式 | 条件值 | 规则ID |
1 | 性别等于 | A1 | sex | = | femal | 1001 |
2 | 气血等于 | A2 | blood | = | weak | 1001 |
3 | 身体状况等于 | A3 | body | = | thin | 1001 |
4 | 腰膝情况等于 | A4 | waist | = | limp | 1001 |
5 | 月经状态等于 | A5 | menses | = | menoxenia | 1001 |
展示结果表
结果ID | 结果名称 | 规则ID |
1 | 乌鸡白凤丸:主治女性气血两虚,身体瘦弱,腰膝酸软,月经不调。 | 1001 |
2.2 编码实现
从数据库结构和数据存储的分析,我们从计算机实现的角度来看就是只要满足症状规则表中规则表达式的值为真,那么就展示规则对应的结果。即计算(A1 && A2 && A3&& A4 && A5)表达式的真假。
2.2.1 调用说明
外围系统调用规则引擎传入参数为:sex=male&blood=weak&body=thin&waist=limp&menses=menoxenia,那么我们拿到这些参数和值后,传入规则引擎,根据传入参数编码和值对比数据库中存储的编码和值。可以得出:
A1=false
A2=true
A3=true
A4=true
A5=true
表达式(A1 && A2 && A3 && A4 && A5)计算结果为false,不展示结果;如果传入参数中sex=female,那么A1=true,表达计算结果为true,则展示相应的结果。
2.2.2 表达式计算示例
importjavax.script.ScriptEngine;
importjavax.script.ScriptEngineManager;
publicclass TestExpress {
public static void main(String[] args)throws Exception {
String expr = "(A1 &&A2 && A3 && A4 && A5)";
ScriptEngineManager manager = newScriptEngineManager();
ScriptEngine engine =manager.getEngineByName("js");
engine.put("A1", true);
engine.put("A2", true);
engine.put("A3", true);
engine.put("A4", true);
engine.put("A5", true);
Object result = engine.eval(expr);
System.out.println(result);
}
}
总结
由于作者水平和认知有限,如有不对的地方请批评和指正。希望本文档可以帮助到您,或者给您一些启发。